import {
  axiosDeleteColumn,
  axiosRenameColumn,
  getColumnsByProject,
  postColumn
} from '@/axios/taskBoard';
import { PayloadAction, createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import {
  addFileTask,
  addSubTask,
  addSubTaskChecklist,
  addTask,
  changeChecklistDate,
  changeSubtaskDate,
  changeTaskDate,
  moveTask,
  moveTaskColumn,
  pinnedTask,
  removeTaskItem,
  setPriority,
  toggleStatusChecklist,
  toggleStatusSubtask,
  toggleStatusTask
} from '../tasks/tasksSlice';
import { moveElement, moveElementColumn } from '@/helpers';

export const getColumns = createAsyncThunk(
  'columns/getColumns',
  async (selectedProjectId: string) => {
    const response = await getColumnsByProject({ params: { project_id: selectedProjectId } });
    return response;
  }
);

export const addColumn = createAsyncThunk<Column, string>(
  'columns/addColumn',
  async (name: string) => {
    const lcls = localStorage.getItem('selectedProjectId') || '';
    const response = await postColumn({ params: { project_id: lcls, name } });
    const newColumn: Column = { tasks: [], id: 0, name: '', ...response };
    return newColumn;
  }
);

export const deleteColumn = createAsyncThunk('columns/deleteColumn', async (id: number) => {
  const projectId = localStorage.getItem('selectedProjectId') || '';
  await axiosDeleteColumn({ params: { id, project_id: projectId } });

  return { id, projectId };
});

export const renameColumn = createAsyncThunk(
  'columns/renameColumn',
  async ({ name, columnId }: { columnId: number; name: string }) => {
    const projectId = localStorage.getItem('selectedProjectId') || '';
    await axiosRenameColumn({ params: { id: columnId, name, project_id: projectId } });
  }
);

export interface ProjectsState {
  columns: Column[];
  error: string | undefined;
  loading: boolean;
  status: 'idle' | 'loading' | 'error' | 'success';
}

const initialState: ProjectsState = {
  columns: [],
  error: undefined,
  loading: false,
  status: 'idle'
};

const getIdx = (state: ProjectsState, action: PayloadAction<any>) => {
  const idx = (arr: Task[] | Column[], id: number) => arr?.findIndex((el) => el.id === id);
  const { colId, taskId, subtaskId = 0, checkId = 0 } = action.payload;
  const checker = (num: number) => (num > -1 ? num : -1);
  const colIdx = checker(idx(state.columns, colId));
  const taskIdx = checker(idx(state.columns[colIdx].tasks, taskId));
  const subtaskIdx = checker(idx(state.columns[colIdx].tasks[taskIdx].subtasks, subtaskId));
  const checkIdx = checker(
    idx(state.columns[colIdx].tasks[taskIdx]?.subtasks[subtaskIdx]?.subtasks, checkId)
  );
  return { colIdx, taskIdx, subtaskIdx, checkIdx };
};

const columnsSlice = createSlice({
  name: 'tasks',
  initialState,
  reducers: {
    setColumns: (state, action) => {
      state.columns = action.payload;
    },
    setTaskItemColumns: (state, action) => {
      const { collId, tasks } = action.payload;
      state.columns = state.columns.map((column) =>
        column.id === collId
          ? {
              ...column,
              tasks: [...tasks],
              selected: false,
              chosen: false
            }
          : { ...column, selected: false, chosen: false }
      );
    },
    setRenameColumn: (state, action) => {
      state.columns = state.columns.map((column) => {
        if (column.id === action.payload.id) {
          return { ...column, name: action.payload.name };
        }
        return column;
      });
    },
    setRenameTask: (state, action) => {
      const { colIdx, taskIdx } = getIdx(state, action);
      state.columns[colIdx].tasks[taskIdx].name = action.payload.name;
    },
    subtaskClose: (state, action) => {
      const { colIdx, taskIdx } = getIdx(state, action);
      state.columns[colIdx].tasks[taskIdx].subtaskOpen = false;
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(getColumns.pending, (state) => {
        state.status = 'loading';
        state.loading = true;
      })
      .addCase(getColumns.fulfilled, (state, action) => {
        state.columns = action.payload;
        state.status = 'success';
        state.loading = false;
      })
      .addCase(getColumns.rejected, (state, action) => {
        state.error = action.error.message;
        state.loading = false;
        state.status = 'error';
      })
      .addCase(addTask.fulfilled, (state, action) => {
        const subtaskOpen = !!action.payload.response.subtasks.length;
        const task = subtaskOpen
          ? { ...action.payload.response, subtaskOpen: subtaskOpen }
          : action.payload.response;
        state.columns.map((col) => {
          if (col.id === +action.payload.columnId) {
            if (col.tasks) return col.tasks.unshift(task);
          }
        });
      })
      .addCase(addColumn.fulfilled, (state, action) => {
        state.columns.push(action.payload);
      })
      .addCase(addSubTask.fulfilled, (state, action) => {
        const { columnId, parentId, response } = action.payload;
        const columnIdx = state.columns.findIndex((col) => col.id === columnId);
        if (columnIdx !== -1) {
          const taskIdx = state.columns[columnIdx].tasks.findIndex((task) => task.id === parentId);
          if (taskIdx !== -1) {
            console.log(response);
            state.columns[columnIdx].tasks[taskIdx] = {
              ...state.columns[columnIdx].tasks[taskIdx],
              subtasks: [response, ...state.columns[columnIdx].tasks[taskIdx].subtasks]
            };
          }
        }
      })
      .addCase(addSubTaskChecklist.fulfilled, (state, action) => {
        const { columnId, parentId, response, grandParentId } = action.payload;
        const columnIdx = state.columns.findIndex((col) => col.id === +columnId);
        if (columnIdx !== -1) {
          const grandParentIdx = state.columns[columnIdx].tasks.findIndex(
            (task) => task.id === grandParentId
          );
          if (grandParentIdx !== -1) {
            const subtaskIdx = state.columns[columnIdx].tasks[grandParentIdx].subtasks.findIndex(
              (task) => task.id === parentId
            );
            if (subtaskIdx !== -1) {
              state.columns[columnIdx].tasks[grandParentIdx].subtasks[subtaskIdx] = {
                ...state.columns[columnIdx].tasks[grandParentIdx].subtasks[subtaskIdx],
                subtasks: [
                  response,
                  ...state.columns[columnIdx].tasks[grandParentIdx].subtasks[subtaskIdx].subtasks
                ]
              };
            }
          }
        }
      })
      .addCase(removeTaskItem.fulfilled, (state, action) => {
        const { id, columnId, parentId, grandParentId } = action.payload;
        const columnIdx = state.columns.findIndex((col) => col.id === columnId);
        if (columnIdx !== -1) {
          if (!parentId && !grandParentId) {
            state.columns[columnIdx].tasks = state.columns[columnIdx].tasks.filter(
              (task: Task) => task.id !== id
            );
          }

          if (parentId && !grandParentId) {
            const parentIdx = state.columns[columnIdx].tasks.findIndex(
              (task) => task.id === parentId
            );
            state.columns[columnIdx].tasks[parentIdx].subtasks = state.columns[columnIdx].tasks[
              parentIdx
            ].subtasks.filter((sub) => sub.id !== id);
          }
        }
      })
      .addCase(moveTask.fulfilled, (state, action) => {
        const { colId, taskNewIndex, taskOldIndex } = action.payload;
        console.log(taskNewIndex, taskOldIndex);
        const colIdx = state.columns.findIndex((col) => col.id === colId);

        state.columns[colIdx].tasks = moveElement({
          arr: state.columns[colIdx].tasks,
          oldIndex: taskOldIndex,
          newIndex: taskNewIndex
        });
      })
      .addCase(moveTaskColumn.fulfilled, (state, action) => {
        const { newColId, oldColId, taskNewIndex, taskOldIndex } = action.payload;
        const oldColIdx = state.columns.findIndex((col) => col.id === oldColId);
        const newColIdx = state.columns.findIndex((col) => col.id === newColId);

        const { oldArr, newArr } = moveElementColumn({
          oldIndex: taskOldIndex,
          newIndex: taskNewIndex,
          oldArr: state.columns[oldColIdx].tasks,
          newArr: state.columns[newColIdx].tasks,
          newColId
        });

        state.columns[newColIdx].tasks = newArr;
        state.columns[oldColIdx].tasks = oldArr;
      })
      .addCase(toggleStatusTask.fulfilled, (state, action) => {
        const { colIdx, taskIdx } = getIdx(state, action);
        state.columns[colIdx].tasks[taskIdx].is_closed = action.payload.status;
        state.columns[colIdx].tasks[taskIdx].pinned =
          state.columns[colIdx].tasks[taskIdx].is_closed &&
          state.columns[colIdx].tasks[taskIdx].pinned
            ? 0
            : state.columns[colIdx].tasks[taskIdx].pinned;
      })
      .addCase(toggleStatusSubtask.fulfilled, (state, action) => {
        const { colIdx, taskIdx, subtaskIdx } = getIdx(state, action);
        state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].is_closed = action.payload.status;
      })
      .addCase(toggleStatusChecklist.fulfilled, (state, action) => {
        const { colIdx, taskIdx, subtaskIdx, checkIdx } = getIdx(state, action);
        state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].subtasks[checkIdx].is_closed =
          action.payload.status;
      })
      .addCase(changeTaskDate.fulfilled, (state, action) => {
        const { colIdx, taskIdx } = getIdx(state, action);
        state.columns[colIdx].tasks[taskIdx].end_date = action.payload.date;
      })
      .addCase(changeSubtaskDate.fulfilled, (state, action) => {
        const { colIdx, taskIdx, subtaskIdx } = getIdx(state, action);
        state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].end_date = action.payload.date;
      })
      .addCase(addFileTask.fulfilled, (state, action) => {
        const { colIdx, taskIdx, subtaskIdx, checkIdx } = getIdx(state, action);
        if (checkIdx !== -1) {
          state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].subtasks[checkIdx].files.push(
            ...action.payload.res.files
          );
          state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].subtasks[checkIdx].files_gid =
            action.payload.res.id;
        }

        if (subtaskIdx > -1 && checkIdx === -1) {
          state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].files.push(
            ...action.payload.res.files
          );
          state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].files_gid =
            action.payload.res.id;
        }

        if (taskIdx && subtaskIdx === -1 && checkIdx === -1) {
          state.columns[colIdx].tasks[taskIdx].files.push(...action.payload.res.files);
          state.columns[colIdx].tasks[taskIdx].files_gid = action.payload.res.id;
        }
      })
      .addCase(deleteColumn.fulfilled, (state, action) => {
        const { id } = action.payload;
        state.columns = state.columns.filter((col) => col.id !== id);
      })
      .addCase(changeChecklistDate.fulfilled, (state, action) => {
        const { colIdx, taskIdx, subtaskIdx, checkIdx } = getIdx(state, action);
        state.columns[colIdx].tasks[taskIdx].subtasks[subtaskIdx].subtasks[checkIdx].end_date =
          action.payload.date;
      })
      .addCase(pinnedTask.fulfilled, (state, action) => {
        const { columnId, pinned, taskId } = action.payload;
        const colIdx = state.columns.findIndex((col) => col.id === columnId);
        const taskIdx = state.columns[colIdx].tasks.findIndex((task) => task.id === taskId);
        const taskPinnedCount = state.columns[colIdx].tasks.filter((task) => task.pinned).length;

        state.columns[colIdx].tasks[taskIdx].pinned = pinned === 0 ? 1 : 0;

        state.columns[colIdx].tasks = moveElement({
          arr: state.columns[colIdx].tasks,
          oldIndex: taskIdx,
          newIndex: pinned === 1 ? taskPinnedCount - 1 : taskPinnedCount
        });
      })
      .addCase(setPriority.fulfilled, (state, action) => {
        const { columnId, priority, taskId } = action.payload;

        const colIdx = state.columns.findIndex((col) => col.id === columnId);
        const taskIdx = state.columns[colIdx].tasks.findIndex((task) => task.id === taskId);
        state.columns[colIdx].tasks[taskIdx].priority_id = priority;
      });
  }
});

export const { setTaskItemColumns, setColumns, setRenameColumn, setRenameTask } =
  columnsSlice.actions;

export default columnsSlice.reducer;
